\documentclass{ii47uji}

\usepackage{graphicx}
\usepackage{titlesec}
\usepackage{fancyhdr}
\usepackage[usenames]{color}
\usepackage{listings}
\usepackage{colortbl}
\usepackage{longtable}
\lstloadlanguages{C}

\lstset{
breaklines=true
}

\usepackage{pifont}

\definecolor{Grey}{rgb}{0.95,0.95,0.95}
% Título del proyecto o de una actividad
\title{Concurrencia en GLib}

\titulacion{Ingeniería Informática} 

% Datos del equipo 
\numeroEquipo{Memoria} % e.g.: \numeroEquipo{05}
\nombreEquipo{} % e.g.: \nombreEquipo{Super-ratón}

\newcommand{\marginalnote}[1]{\mbox{}\marginpar{\raggedright\hspace{0pt}#1}}



% Datos de los participantes en el proyecto (o en esta actividad cooperativa)
\nombres{}{Víctor Centelles Julián}{William Viana Soares}
\emails{}{al073438@alumail.uji.es}{al081521@alumail.uji.es}
\roles{}{}{}

% Para actividades individuales:
% \nombres{}{}{Apellido(s) 1, Nombre 1}{}
% \emails{}{}{email 1}{}
% \roles{}{}{}{}

\date{\today}

\begin{document}

\maketitle

% Resumen en el informe del proyecto (no es necesario en una actividad)
 \begin{abstract}
 Memoria al estudio de concurrencia en el escritorio Gnome. En concreto, se van a exponer las características de la librería GLib.
 \end{abstract}

\tableofcontents
%\pagebreak

\section{Introducción a GTK+}

\subsection{Introducción}
Los prímeros capítulos de este documento se centran en un pequeño tutorial en la creación de pequeñas aplicaciones para \texttt{GTK+}. De este modo, se obtendrán los conocimientos necesarios para poder realizar una pequeña aplicación gráfica que agrupe las príncipales ideas de concurrencia que se verán a lo largo de este documento.


\subsection{Primeros pasos}
Vamos a introducirnos en la programación con GTK+ viendo una serie de ejemplos para ilustrar su conportamiento. Para acabar, se mostrará al lector el típico ejemplo de ``Hello world''.

Lo primero que necesitamos para ello es dibujar una ventana:

\lstset{showspaces=false,backgroundcolor=\color{Grey},basicstyle=\small,stringstyle=\ttfamily,numbers=left,numberstyle=\tiny}
\begin{lstlisting}[language=C]
 #include <gtk/gtk.h>

 int main (int argc, char *argv[]){

   GtkWidget *window;
   gtk_init(&argc, &argv);
   window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
   gtk_widget_show(window);
   gtk_main ();
   return 0;

 }
\end{lstlisting}


\paragraph{\textbf{Cómo funciona}:}
En la primera línea (\texttt{<gtk/gtk.h>}) incluimos las librería de cabeceras necesarias para trabajar con GTK+ (incluyengo GLib). El paso siguiente es declarar un puntero a la estructura \texttt{GtkWidget}.

Acto seguido lo que hacemos es iniciar las librerias de GTK+ mediante la instrucción \texttt{gtk\_init}, a la cual le pasamos como argumentos los que ha recibido el programa por la línea de comandos: \texttt{argc} y \texttt{argv}. Esto permite a GTK+ parsear algún parámetro si es necesario. Es importante notar que siempre se debe inicializar GTK+ antes de llamar a cualquiera de las funciones que proporciona dicha librería.

Lo más importante del ejemplo es la línea donde se llama a la función \texttt{gtk\_window\_new}. Su prototipo es:
\begin{center}
 \texttt{GtkWidget* gtk\_window\_new (GtkWindowType type);}
\end{center}

donde \texttt{type} dependiendo de la finalidad de la ventana puede tomar los valores de \texttt{GTK\_WINDOW\_TOPLEVEL} (ventana con marco estándar) o \texttt{GTK\_WINDOW\_POPUP} (ventana sin marco adecuda para los cuadros de diálogo). 

La llamada a \texttt{gtk\_window\_new} sitúa la ventana en la memoria, donde el programador tendrá la oportunidad de poblarla una con widgets, modificar su tamaño, cambiar el título de la ventana, etc. antes de mostrarlo en pantalla. Para hacer que la ventana apararezca en la pantalla, se llama a la función \texttt{gtk\_widget\_show}:
  \begin{center}
   \texttt{gtk\_widget\_show(window);}
  \end{center}

La última llamada que se realiza es a \texttt{gtk\_main}. Esta función clave arranca el proceso de interactividad pasando el control a GTK+ y finaliza hasta que se realice una llamada a \texttt{gtk\_quit}. En nuestro ejemplo, esta última función no aperece, por lo que nuestro programa no terminará nunca. Esto se podrá solucionar más adelante cuando veamos las señales.

Para compilar el ejemplo, utilizamos la siguiente instrucción:
\begin{lstlisting}[language=C]
 gcc -Wall -g gtk01.c -o ejemplo1 `gtk-config --cflags` `gtk-config --libs`
\end{lstlisting}

Y el resultado obtenido se puede ver en la figura \ref{img:ej01}.

\begin{figure}[ht!]
\begin{center}
\scalebox{0.5}{\includegraphics{imagenes/ej01.jpg}}
\end{center}
\caption{Primer ejemplo con Gtk+}
\label{img:ej01}
\end{figure}

\subsection{Eventos, Signals y Callbacks}
Todas las librerías de GUI's poseen un mecanismo de intercomunicación con el usuario que les permite ejecutar código en respuesta a las acciones de éste. GTK+ tiene su propio sistema de eventos y de ``escuchadores'' de eventos, conocidos como \textit{signals} y \textit{callbacks}, respectivamente.

Un \texttt{signal} en GTK+ es emitida por un \texttt{GtkObject} cuando se produce una interacción del usuario (pulsado de un botón, conbinación de teclas, etc. La función conectada a la señal que se ejecuta cuando se produce esta última es lo que se conoce como función \textit{callback}.

El programador de GTK+ sólo se tiene que preocupar de escribir y conectar las funciones \textit{callback} a las señales pertinentes, puesto que el código de la emisión de señales (\textit{signals}) es interno de cada \textit{widget}.

El prototipo de de una función \textit{callback} es el siguiente:

\begin{center} \texttt{void a\_callback\_function ( GtkWidget *widget, gpointer user\_data );}\end{center}

dónde:
  \begin{itemize}
   \item El primer parámetro es un puntero al \textit{widget} que emite la señal.
   \item El segundo, un puntero a los datos pasados a la función. El programador puede usar este puntero para cualquier proposito.
  \end{itemize}
  
La acción de conectar una función \textit{callback} a una determinada señal es un paso sencillo. Simplemente hay que llamar a la función \texttt{g\_signal\_connect}, cuyo prototipo es:

\begin{center} \texttt{gulong gtk\_signal\_connect (gpointer *object, const gchar *name, 
                          GCallback func, gpointer user\_data)} \end{center}

dónde:
  \begin{itemize}
   \item \texttt{object}: \textit{widget} que emite la señal.
   \item \texttt{name}: nombre de la señal que queremos capturar.
   \item \texttt{func}: función a la que queremos que se llame cuando se `cace' la señal.
   \item \texttt{user\_data}: datos que queremos pasarle a esta función.
  \end{itemize}

A continuación podemos ver un ejemplo para ilustrar el comportamiento de las funciones anteriores:
\begin{lstlisting}[language=C]
#include <gtk/gtk.h>
#include <stdio.h>

static int count = 0;

void pulsar_boton(GtkWidget *boton, gpointer data){
  if( count ) printf("%s pulsado %d veces \n", (char *) data, ++count);
  else        printf("%s pulsado %d vez   \n", (char *) data, ++count);
}

int main (int argc, char *argv[]){
  GtkWidget *window;
  GtkWidget *boton;

  gtk_init(&argc, &argv);
  window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
  boton = gtk_button_new_with_label("Pulse el boton para escribir en consola");
  gtk_container_add(GTK_CONTAINER(window), boton);

  gtk_signal_connect(GTK_OBJECT (boton), "clicked", \
                GTK_SIGNAL_FUNC (pulsar_boton), "Boton de ejemplo");

  gtk_widget_show(boton);
  gtk_widget_show(window);

  gtk_main();

  return 0;
}

\end{lstlisting}
 Cada vez que el usuario apreta el botón (creado mediante la función \texttt{gtk\_button\_new\_with\_label}) se incrementa la variable estática \texttt{count} y se imprime un mensaje por consola con el número de veces que se ha presionado el botón desde el inicio de la ejecución del programa. 
 
 La función \textit{callback} \texttt{pulsar\_boton} está conectada a la señal \texttt{clicked} del widget \texttt{boton} usando la funcion \texttt{gtk\_signal\_connect}. Destacar que el nombre del botón (``\texttt{Boton de ejemplo}'') es pasado como parámetro a la función \textit{callback} \texttt{pulsar\_boton}.
 
 Por otro lado, la función \texttt{gtk\_button\_new\_with\_label(char * label)} crea, como su propio nombre indica, un botón nuevo con la etiqueta especificada como argumento.
  
  
 
 Podemos ver una captura de la ejecución del mismo en la figura \ref{img:ej02}.
 
\begin{figure}[ht!]
\begin{center}
\scalebox{0.5}{\includegraphics{imagenes/ej02.jpg}}
\end{center}
\caption{Ejemplo con \textit{signals} y \textit{callbacks} }
\label{img:ej02}
\end{figure}



\subsection{Hola Mundo}
Una vez vistos los eventos, dejamos al lector el estudio de este \textit{Hello World}. Aquí aparecen nuevos eventos como la señal \textit{destroy}. Cada uno de los bloques tiene un comentario explicativo que describe las acciones que realizan cada una de las instrucciones del código.

\begin{lstlisting}[language=C,basicstyle=\scriptsize]
#include <gtk/gtk.h>

/* Esta es una funcion respuesta (callback). Sus argumentos
   son ignorados por en este ejemplo */
void hello (GtkWidget *widget, gpointer data)
{
    g_print ("Hola mundo\n");
}

gint delete_event(GtkWidget *widget, GdkEvent *event, gpointer data)
{
    /* si se devuelve FALSE al administrador de llamadas
     * "delete_event", GTK emitira la senyal de destruccion
     * "destroy". Esto es util para dialogos emergentes del
     * tipo: Seguro que desea salir?

    g_print ("Ha ocurrido un evento delete\n");

    /* Cambiando TRUE por FALSE la ventana se destruira con
     * "delete_event"*/

    return (TRUE);
}

/* otra respuesta */
void destroy (GtkWidget *widget, gpointer data)
{
    gtk_main_quit ();
}

int main (int argc, char *argv[])
{

    /* GtkWidget es el tipo de almacenamiento usado para los
     * widgets */
     
    GtkWidget *ventana;
    GtkWidget *boton;

    /* En cualquier aplicacion hay que realizar la siguiente
     * llamada. Los argumentos son tomados de la linea de comandos
     * y devueltos a la aplicacion. */

    gtk_init (&argc, &argv);
    
    /* creamos una ventana nueva */
    
    ventana = gtk_window_new (GTK_WINDOW_TOPLEVEL);
    
    /* Cuando la ventana recibe la senyal "delete_event" (emitida
     * por el gestor de ventanas, normalmente mediante la opcion
     * 'close', o en la barra del titulo) hacemos que llame a la
     * funcion delete_event() tal y como ya hemos visto. Los datos
     * pasados a la funcion de respuesta son NULL, y seran ignorados. */
     
    gtk_signal_connect (GTK_OBJECT (ventana), "delete_event",
                        GTK_SIGNAL_FUNC (delete_event), NULL);

    /* Aqui conectamos el evento "destroy" con el administrador de
     * senyales. El evento se produce cuando llamamos a
     * gtk_widget_destroy() desde la ventana o si devolvemos 'FALSE'
     * en la respuesta "delete_event". */
     
    gtk_signal_connect (GTK_OBJECT (ventana), "destroy",
                        GTK_SIGNAL_FUNC (destroy), NULL);
    
    /* establecemos el ancho del borde de la ventana. */
    
    gtk_container_border_width (GTK_CONTAINER (ventana), 10);
    
    /* creamos un boton nuevo con la  etiqueta "Hola mundo" */
    
    boton = gtk_button_new_with_label ("Hola mundo");
    
    /* Cuando el boton recibe la senyal "clicked" llama a la
     * funcion hello() pasandole NULL como argumento. (La
     * funcion ya ha sido definida arriba). */
     
    gtk_signal_connect (GTK_OBJECT (boton), "clicked",
                        GTK_SIGNAL_FUNC (hello), NULL);
    
    /* Esto hara que la ventana sea destruida llamando a
     * gtk_widget_destroy(ventana) cuando se produzca "clicked". Una
     * vez mas la senyal de destruccion puede provenir del gestor
     * de ventanas o de aqui. */
     
     gtk_signal_connect_object (GTK_OBJECT (boton), "clicked",
                               GTK_SIGNAL_FUNC (gtk_widget_destroy),
                               GTK_OBJECT (ventana));
    
    /* Ahora empaquetamos el boton en la ventana (usamos un gtk
     * container ). */
    gtk_container_add (GTK_CONTAINER (ventana), boton);
    
    /* El ultimo paso es representar el nuevo widget... */
    
    gtk_widget_show (boton);
    
    /* y la ventana */
    gtk_widget_show (ventana);
    
    /* Todas las aplicaciones basadas en GTK deben tener una llamada
     * gtk_main() ya que el control termina justo aqui y debe
     * esperar a que suceda algun evento */

    gtk_main ();
    
    return 0;
}

\end{lstlisting}

En la figura \ref{img:ej03} se puede ver una captura del código anterior.
 
\begin{figure}[ht!]
\begin{center}
\scalebox{0.5}{\includegraphics{imagenes/ej03.jpg}}
\end{center}
\caption{Ejemplo ``\textit{Hello World!}'' }
\label{img:ej03}
\end{figure}

\subsection{Widgets}
A continuación se da una breve descripción de los principales widgets que se pueden utilizar con gtk+. No es la intención de este artículo mostrar todos los widgets ni todas las posibilidades que ofrecen, sino dar un imagen general de la librería de Gtk+. Así pues, si el lector desea saber más sobre ellos le recomendamos que se busque en la extensa documentación existente que se puede encontrar en la red (p.e. \href{http://library.gnome.org}{documentación de GNOME}, etc.).

\subsubsection{Packing Box Widgets}
Lo más común para ``empaquetar'' o ``asociar''widgets es utilizar \textit{cajas}. Podemos entender como \textit{caja} un widget invisble que puede contener varios widgets de dos maneras distintas: bien verticalmente, o bien en horizontal. Si lo hacemos de la primera forma, los objetos se insertarán de izquierda a derecha (o al revés, dependiendo de la llamada), y si se hace de la segunda, de arriba a abajo o al revés. Para utilizar dichas cajas, tenemos las siguientes funciones:
  
  \begin{center}
     \texttt{GtkWidget * gtk\_hbox\_new (gboolean homogeneous, gint spacing);\\
     GtkWidget * gtk\_vbox\_new (gboolean homogeneous, gint spacing);}
  \end{center}
  dónde:
    \begin{itemize}
     \item \texttt{homogeneous}: establece si cada objeto en la caja tiene el mismo tamaño.
     \item \texttt{spacing}: espacio entre widgets en \textit{pixels}.
    \end{itemize}
    
Una vez ya tenemos creados las cajas, el siguiente paso es asignarles widgets. Para ello, se disponen de las siguientes funciones:
  
  \begin{center}
   \texttt{void gtk\_box\_pack\_start (GtkBox *box, GtkWidget *child, gboolean expand,\\ gboolean fill, guint padding);}\\
   \texttt{void gtk\_box\_pack\_end (GtkBox *box, GtkWidget *child, gboolean expand,\\ gboolean fill, guint padding);}
  \end{center}
dónde:
  \begin{itemize}
   \item \texttt{box:} puntero a la caja dónde se quiere empaquetar el \textit{widget}.
   \item \texttt{child:} puntero del \textit{widget} a empaquetar.
   \item \texttt{expand:} determina si los \textit{widgets} son expandidos en la caja para rellenar todo el espacio de la misma (\texttt{TRUE}) o si por el contrario no se usa el espacio extra dentro de la caja (\texttt{FALSE}).
   \item \texttt{fill:} establece si el espacio extra se mete dentro de los objetos (\texttt{TRUE}) o como relleno extra (\texttt{FALSE}). Sólo tiene efecto si el argumento de expansión también es \texttt{TRUE}.
   \item \texttt{padding:} espacio adicional a la derecha e izquierda en \textit{pixels}.
  \end{itemize}
  
A continuación se puede visualizar un ejemplo de la utilización de las funciones anteriores, además de una captura de la ejecución (figura \ref{img:packingbox}) y un gráfico sobre como se encuentran distribuidas realmente las etiquetas (figura \ref{img:pbox}):
  
\begin{lstlisting}[language=C,basicstyle=\scriptsize]
#include <gtk/gtk.h>
#include <stdio.h>

void closeApp ( GtkWidget *window, gpointer data) {
  gtk_main_quit();
}

gboolean delete_event(GtkWidget *widget, GdkEvent *event, gpointer data){
  printf("In delete_event\n");
  return FALSE;
}


int main (int argc, char *argv[]) {
  GtkWidget *window;
  GtkWidget *label1, *label2, *label3;
  GtkWidget *hbox;
  GtkWidget *vbox;

  gtk_init(&argc, &argv);
  window = gtk_window_new(GTK_WINDOW_TOPLEVEL);

  gtk_window_set_title(GTK_WINDOW(window), "Ejemplo de Packing Box");
  gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
  gtk_window_set_default_size(GTK_WINDOW(window), 300, 200);

  gtk_signal_connect ( GTK_OBJECT (window), "destroy",
                       GTK_SIGNAL_FUNC ( closeApp), NULL);
  gtk_signal_connect ( GTK_OBJECT (window), "delete_event",
                       GTK_SIGNAL_FUNC ( delete_event), NULL);

  label1 = gtk_label_new("Etiqueta 1");
  label2 = gtk_label_new("Etiqueta 2");
  label3 = gtk_label_new("Etiqueta 3");

  hbox = gtk_hbox_new ( TRUE, 5 );
  vbox = gtk_vbox_new ( FALSE, 10);

  gtk_box_pack_start(GTK_BOX(vbox), label1, TRUE, FALSE, 5);
  gtk_box_pack_start(GTK_BOX(vbox), label2, TRUE, FALSE, 5);
  gtk_box_pack_start(GTK_BOX(hbox), vbox, FALSE, FALSE, 5);
  gtk_box_pack_start(GTK_BOX(hbox), label3, FALSE, FALSE, 5);

  gtk_container_add(GTK_CONTAINER(window), hbox);
  gtk_widget_show_all(window);
  gtk_main ();

  return 0;
}

\end{lstlisting}

\begin{figure}[ht!]
\begin{center}
\scalebox{0.52}{\includegraphics{imagenes/packingbox.jpg}}
\end{center}
\caption{Ejemplo de ``Packing Box'' }
\label{img:packingbox}
\end{figure}

\begin{figure}[ht!]
\begin{center}
\scalebox{0.5}{\includegraphics{imagenes/pbox.jpg}}
\end{center}
\caption{Distribución gráfica de las etiquetas del ejemplo de la figura \ref{img:packingbox} }
\label{img:pbox}
\end{figure}


\subsubsection{Buttons}
En ejemplos anteriores ya hemos visto por encima los botones gracias a la sentencia \texttt{GtkButton}. De dicho widget se heredan varios tipos de botones como son \texttt{GtkToggleButton}, \texttt{GtkCheckButton} y \texttt{GtkRadioButton}. Cada uno de ellos es desdendiente de la clase anterior (GtkToggleButton hereda los atributos de GtkButton, etc.).\\


\textbf{GtkToggleButton}\\
El GtkToggleButton es idéntico al GtkButton excepto en una cosa, posee un atributo que indica el estado en el que se encuentra (en otras palabras, si se encuentra o no pulsado). Cuando el usuario realiza un \textit{click} sobre un \texttt{GtkToggleButton}, se emite una señal ``\texttt{clicked}'' que es la manera usual de cambiar el estado del botón.

El API para \texttt{GtkToggleButton} es la siguiente:
  
\begin{lstlisting}[language=C]
 GtkWidget* gtk_toggle_button_new (void);
 GtkWidget* gtk_toggle_button_new_with_label (const gchar *label);
 gboolean   gtk_toggle_button_get_active (GtkToggleButton *toggle_button);
 void       gtk_toggle_button_set_active (GtkToggleButton *toggle_button,
                                          gboolean is_active);
\end{lstlisting}

\textbf{GtkCheckButton}
El \texttt{GtkCheckButton} tiene la misma funcionalidad que el \texttt{GtkToggleButton}, lo único que en vez de representarse mediante un botón, \texttt{GtkToggleButton} lo hace mediante un \textit{checkbox}. Su API es la siguiente:
  
\begin{lstlisting}[language=C]
 GtkWidget* gtk_check_button_new (void);
 GtkWidget* gtk_check_button_new_with_label (const gchar *label);
\end{lstlisting}

\textbf{GtkRadioButton}
Son los habituales botones que permetin realizar una selección entre varias opciones. De cada grupo de \texttt{GtkRadioButton} sólo se puede seleccionar uno. Su API se describe a continuación:
  
\begin{lstlisting}[language=C]
 GtkWidget* gtk_radio_button_new (GSList *group);
 GtkWidget* gtk_radio_button_new_from_widget (GtkRadioButton *group);
 GtkWidget* gtk_radio_button_new_with_label (GSList *group, const gchar *label);
 void   gtk_radio_button_set_group (GtkRadioButton *radio_button, GSList *group);
 GSList*    gtk_radio_button_get_group (GtkRadioButton *radio_button);
\end{lstlisting}

Para ver en acción los cuatro tipos de botones (\texttt{GtkButton}, \texttt{GtkToggleButton}, \texttt{GtkCheckButton} y \texttt{GtkRadioButton}) el lector puede estudiar y probar el código del siguiente programa:
   
\begin{lstlisting}[language=C,basicstyle=\scriptsize]
#include <gtk/gtk.h>
#include <stdio.h>

GtkWidget *togglebutton;
GtkWidget *checkbutton;
GtkWidget *radiobutton1, *radiobutton2;

void closeApp ( GtkWidget *window, gpointer data){
  gtk_main_quit();
}

void add_widget_with_label(GtkContainer * box, gchar * caption, GtkWidget * widget) {
  GtkWidget *label = gtk_label_new (caption);
  GtkWidget *hbox = gtk_hbox_new (TRUE, 4);
  gtk_container_add(GTK_CONTAINER (hbox), label);
  gtk_container_add(GTK_CONTAINER (hbox), widget);
  gtk_container_add(box, hbox);
}

void print_active(char * button_name, GtkToggleButton *button){
  gboolean active = gtk_toggle_button_get_active(button);
  printf("%s es %s\n", button_name, active?"activo":"no activo");
}

void button_clicked(GtkWidget *button, gpointer data){
  print_active("Checkbutton",  GTK_TOGGLE_BUTTON(checkbutton));
  print_active("Togglebutton", GTK_TOGGLE_BUTTON(togglebutton));
  print_active("Radiobutton1", GTK_TOGGLE_BUTTON(radiobutton1));
  print_active("Radiobutton2", GTK_TOGGLE_BUTTON(radiobutton2));
  printf("\n");
}

gint main (gint argc, gchar *argv[]){
  GtkWidget *window;
  GtkWidget *button;
  GtkWidget *vbox;
  
  gtk_init (&argc, &argv);
  
  window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
  
  gtk_window_set_default_size(GTK_WINDOW(window), 200, 200);
  gtk_signal_connect ( GTK_OBJECT (window), "destroy",
                       GTK_SIGNAL_FUNC (closeApp), NULL);
  
  button = gtk_button_new_with_label("Ok");
  togglebutton = gtk_toggle_button_new_with_label("Toggle");
  checkbutton = gtk_check_button_new();
  radiobutton1 = gtk_radio_button_new(NULL);
  radiobutton2 = gtk_radio_button_new_from_widget(GTK_RADIO_BUTTON(radiobutton1));
  vbox = gtk_vbox_new (TRUE, 4);
  
  add_widget_with_label (GTK_CONTAINER(vbox), "ToggleButton:", togglebutton);
  add_widget_with_label (GTK_CONTAINER(vbox), "CheckButton:", checkbutton);
  add_widget_with_label (GTK_CONTAINER(vbox), "Radio 1:", radiobutton1);
  add_widget_with_label (GTK_CONTAINER(vbox), "Radio 2:", radiobutton2);
  add_widget_with_label (GTK_CONTAINER(vbox), "Button:", button);
  
  gtk_signal_connect(GTK_OBJECT(button), "clicked",
                     GTK_SIGNAL_FUNC(button_clicked), NULL);
  
  gtk_container_add(GTK_CONTAINER(window), vbox);
  gtk_widget_show_all(window);
  
  gtk_main ();
  return 0;
}

\end{lstlisting}

La ejecución del anterior programa da como resultado lo que se puede ver en la figura \ref{img:buttons}:

\begin{figure}[ht!]
\begin{center}
\scalebox{0.52}{\includegraphics{imagenes/buttons.jpg}}
\end{center}
\caption{Ejemplo con diferentes tipos de botones }
\label{img:buttons}
\end{figure}

\subsubsection{Labels}
Las etiquetas (``\textit{labels}'') son elementos muy usados en GTK y son bastante simples de manejar. No pueden emitir señales ya que no tienen ventanas X window asociadas. 

Para crear una nueva etiqueta se usa la función \texttt{gtk\_label\_new}:

\begin{center}\texttt{GtkWidget *gtk\_label\_new( char *str );}\end{center}

El único argumento (\texttt{str}) es la cadena de texto que se quiere mostrar. Si se desea cambiarla después de que haya sido creada se utiliza:

\begin{center}\texttt{void gtk\_label\_set( GtkLabel *label, char *str );}\end{center}

En este caso el primer argumento es la etiqueta ya creada (cambiado su tipo mediante la macro \texttt{GTK\_LABEL()}) y el segundo es la nueva cadena. El espacio que necesite la nueva etiqueta se ajustará automáticamente, si es necesario.

Para obtener el estado de la cadena en un momento dado existe la función:

\begin{center}\texttt{void gtk\_label\_get( GtkLabel *label, char **str );}\end{center}

El primer argumento es la etiqueta, mientras que el segundo es el valor devuelto para la cadena. 


\subsubsection{Entry}
El \textit{widget} \texttt{Entry} permite mostrar e introducir texto en una línea de un cuadro de diálogo. El texto se puede poner con llamadas a funciones que permiten reemplazar, preañadir o añadir el texto al contenido actual del \textit{widget} \texttt{Entry}.

Hay dos funciones para crear un \textit{widget} \texttt{Entry}:

    \begin{center}\texttt{GtkWidget *gtk\_entry\_new( void );\\
    GtkWidget *gtk\_entry\_new\_with\_max\_length( guint16 max );}\end{center}

La primera sirve para crear un nuevo \textit{widget} \texttt{Entry}, mientras que la segunda crea el \textit{widget} y además establece un límite en la longitud del texto que irá en el mismo.

Por otro lado, existen varias funciones que sirven para alterar el que texto que se está en el \textit{widget} \texttt{Entry}.
    \begin{center}\texttt{void gtk\_entry\_set\_text     ( GtkEntry *entry, const gchar *text );\\
    void gtk\_entry\_append\_text  ( GtkEntry *entry, const gchar *text );\\
    void gtk\_entry\_prepend\_text ( GtkEntry *entry, const gchar *text );}\end{center}

La función \texttt{gtk\_entry\_set\_text} cambia el contenido actual del \textit{widget} \texttt{Entry}. Las funciones \texttt{gtk\_entry\_append\_text} y \texttt{gtk\_entry\_prepend\_text} permiten añadir o preañadir texto.

Las función siguiente permite decir donde poner el punto de inserción.

\begin{center}\texttt{void gtk\_entry\_set\_position( GtkEntry *entry, gint position );}\end{center}

Se pueden obtener los contenidos del \textit{widget} llamando a la función que se describe a continuación. Obtener los contenidos del \textit{widget} puede ser útil en las funciones de llamada descritas más adelante.

\begin{center}\texttt{gchar *gtk\_entry\_get\_text( GtkEntry *entry );}\end{center}

Si quiere impedir que alguien cambie el contenido del \textit{widget} escribiendo en él, utilice la función

\begin{center}\texttt{void gtk\_entry\_set\_editable( GtkEntry *entry, gboolean editable );}\end{center}

Esta función permite camiar el estado de edición de un \textit{widget} \texttt{Entry}, siendo el argumento editable \texttt{TRUE} o \texttt{FALSE}.

Si estamos usando el \textit{widget} \texttt{Entry} en un sitio donde no deseamos que el texto que se introduce sea visible, como por ejemplo cuando estamos introduciendo una clave, podemos utilizar la función siguiente, que también admite como argumento una valor booleano.

\begin{center}\texttt{void gtk\_entry\_set\_visibility( GtkEntry *entry, gboolean  visible );}\end{center}

Se puede seleccionar una región del texto utilizando la siguiente función. Esta función se puede utilizar después de poner algún texto por defecto en el widget, haciéndole fácil al usuario eliminar este texto. 

\begin{center}\texttt{void gtk\_entry\_select\_region( GtkEntry *entry, gint start, gint end );}\end{center}

En las lineas siguientes se muestra un ejemplo con las funciones anteriores mientras que en la figura \ref{img:entry} posterior al código se puede ver el resultado de la ejecución del mismo.
 
\begin{lstlisting}[language=C,basicstyle=\scriptsize]
#include <gtk/gtk.h>
#include <stdio.h>

void enter_callback(GtkWidget *widget, GtkWidget *entry){
  gchar *entry_text;
  entry_text = gtk_entry_get_text(GTK_ENTRY(entry));
  printf("Entry contents: %s\n", entry_text);
}

void entry_toggle_editable (GtkWidget *checkbutton,GtkWidget *entry){
  gtk_entry_set_editable(GTK_ENTRY(entry),
                         GTK_TOGGLE_BUTTON(checkbutton)->active);
}

void entry_toggle_visibility (GtkWidget *checkbutton, GtkWidget *entry){
  gtk_entry_set_visibility(GTK_ENTRY(entry), GTK_TOGGLE_BUTTON(checkbutton)->active);
}

int main (int argc, char *argv[]){

    GtkWidget *window;
    GtkWidget *vbox, *hbox;
    GtkWidget *entry;
    GtkWidget *button;
    GtkWidget *check;

    gtk_init (&argc, &argv);

    /* crear una nueva ventana */
    window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
    gtk_widget_set_usize( GTK_WIDGET (window), 200, 100);
    gtk_window_set_title(GTK_WINDOW (window), "GTK Entry");
    gtk_signal_connect(GTK_OBJECT (window), "delete_event", (GtkSignalFunc) gtk_exit, NULL);

    vbox = gtk_vbox_new (FALSE, 0);
    gtk_container_add (GTK_CONTAINER (window), vbox);
    gtk_widget_show (vbox);

    entry = gtk_entry_new_with_max_length (50);
    gtk_signal_connect(GTK_OBJECT(entry), "activate", GTK_SIGNAL_FUNC(enter_callback), entry);
    gtk_entry_set_text (GTK_ENTRY (entry), "hello");
    gtk_entry_append_text (GTK_ENTRY (entry), " world");
    gtk_entry_select_region (GTK_ENTRY (entry), 0, GTK_ENTRY(entry)->text_length);
    gtk_box_pack_start (GTK_BOX (vbox), entry, TRUE, TRUE, 0);
    gtk_widget_show (entry);

    hbox = gtk_hbox_new (FALSE, 0);
    gtk_container_add (GTK_CONTAINER (vbox), hbox);
    gtk_widget_show (hbox);

    check = gtk_check_button_new_with_label("Editable");
    gtk_box_pack_start (GTK_BOX (hbox), check, TRUE, TRUE, 0);
    gtk_signal_connect (GTK_OBJECT(check), "toggled", GTK_SIGNAL_FUNC(entry_toggle_editable), 
                        entry);
    gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(check), TRUE);
    gtk_widget_show (check);
    
    check = gtk_check_button_new_with_label("Visible");
    gtk_box_pack_start (GTK_BOX (hbox), check, TRUE, TRUE, 0);
    gtk_signal_connect (GTK_OBJECT(check), "toggled", GTK_SIGNAL_FUNC(entry_toggle_visibility),
                        entry);
    gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(check), TRUE);
    gtk_widget_show (check);

    button = gtk_button_new_with_label ("Close");
    gtk_signal_connect_object (GTK_OBJECT (button), "clicked", GTK_SIGNAL_FUNC(gtk_exit),
                               GTK_OBJECT (window));
    gtk_box_pack_start (GTK_BOX (vbox), button, TRUE, TRUE, 0);
    GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
    gtk_widget_grab_default (button);
    gtk_widget_show (button);
    
    gtk_widget_show(window);

    gtk_main();
    return(0);
}
\end{lstlisting}


\begin{figure}[ht!]
\begin{center}
\scalebox{0.52}{\includegraphics{imagenes/entry.jpg}}
\end{center}
\caption{Ejemplo de entrada de texto }
\label{img:entry}
\end{figure}


\subsubsection{File selection}

El \textit{widget} de selección de ficheros proporciona una forma rápida y sencilla de mostrar un cuadro de diálogo para la selección de un fichero. El propio \textit{widget} proporciona los botones Aceptar, Cancelar y Ayuda as, como se verá más adelante, de los punteros a los \textit{widgets} contenidos en él. 

Para crear un nuevo cuadro de diálogo de selección de ficheros se tiene que usar la siguiente función:

\begin{center}\texttt{GtkWidget *gtk\_file\_selection\_new( gchar *title );}\end{center}

Para poner el nombre del fichero en el cuadro de diálogo, por ejemplo para poder utilizar un directorio o un fichero por defecto, utilice la función:

\begin{center}\texttt{void gtk\_file\_selection\_set\_filename( GtkFileSelection *filesel, gchar *filename );}\end{center}

Para obtener el texto que el usuario ha introducido, utilice la función:

\begin{center}\texttt{gchar *gtk\_file\_selection\_get\_filename( GtkFileSelection *filesel );}\end{center}

Existen también punteros a los diferente widgets que contiene el cuadro de diálogo. Son los siguientes:
\begin{itemize}
 \item \texttt{dir\_list}
 \item \texttt{file\_list}
 \item \texttt{selection\_entry}
 \item \texttt{selection\_text}
 \item \texttt{main\_vbox}
 \item \texttt{ok\_button}
 \item \texttt{cancel\_button}
 \item \texttt{help\_button}
\end{itemize}

Lo más probable es que sólo utilice los punteros \texttt{ok\_button}, \texttt{cancel\_button}, y \texttt{help\_button} para controlar cuando se pulsan.

Aquí incluímos un ejemplo, donde se puede ver que no es muy complicado crear un \textit{widget} para la selección de ficheros. Aunque aparezca el botón de ayuda en la pantalla, no hace nada y no tiene ninguna señal conectada. Justo a continuación se puede ver en la figura \ref{img:fichsel} el resultado de la ejecución del mismo.

\begin{lstlisting}[language=C,basicstyle=\scriptsize]
#include <gtk/gtk.h>
  
/* Obtener el nombre del fichero e imprimirlo en la consola */
void file_ok_sel (GtkWidget *w, GtkFileSelection *fs){
   g_print ("%s\n", gtk_file_selection_get_filename (GTK_FILE_SELECTION (fs)));
}

void destroy (GtkWidget *widget, gpointer data){
   gtk_main_quit ();
}

int main (int argc, char *argv[]){
   GtkWidget *filew;

   gtk_init (&argc, &argv);

   /* Crear un nuevo widget de seleccion de ficheros */
   filew = gtk_file_selection_new ("File selection");

   gtk_signal_connect (GTK_OBJECT (filew), "destroy", (GtkSignalFunc) destroy, &filew);
        
   /* Conectar el ok_button con la funcion file_ok_sel */
   
   gtk_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION (filew)->ok_button),
                            "clicked", (GtkSignalFunc) file_ok_sel, filew );
 
   /* Conectar el cancel_button con la destruccion del widget */
   gtk_signal_connect_object (GTK_OBJECT (GTK_FILE_SELECTION (filew)->cancel_button),
                        "clicked", (GtkSignalFunc) gtk_widget_destroy, GTK_OBJECT (filew));
        
   /* Damos el nombre del fichero, como si fuese un cuadro de dialogo para
      grabar ficheros y estuviesemos dando un nombre por defecto */
   gtk_file_selection_set_filename (GTK_FILE_SELECTION(filew), 
                                         "penguin.png");
        
   gtk_widget_show(filew);
   gtk_main ();
   return 0;
}
\end{lstlisting}

\begin{figure}[ht!]
\begin{center}
\scalebox{0.52}{\includegraphics{imagenes/fichsel.jpg}}
\end{center}
\caption{Ejemplo de selector de ficheros}
\label{img:fichsel}
\end{figure}




\newpage
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\section{Concurrencia en la librería GLib}

\subsection{Introducción}

La librería \textbf{GLib\begin{small}™\end{small}} es una de las más importantes que existen en GNOME (GNU Network Object Model Environment). Junto con la librería \textbf{GTK+}, se puede considerar como uno de los pilares en las que sustentan todas las aplicaciones de dicho escritorio.

En este documento va a poder encontrar con las principales opciones que ofrece la libreria GLib para de trabajar sobre procesos concurrentes. La librería GLib es mucho más extensa que lo que puede encontrar en este documento, por lo que si busca más información sobre GLib que no se encuentre dentro de la temática citada, existe multitud de literatura existente\footnote{Sobre todo en línea, como por ejemplo en la \href{http://library.gnome.org}{documentación de GNOME} o en páginas como \href{http://www.es.gnome.org/}{GNOME Hispano}.}.




%% HILOS EN GLIB %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\subsection{Hilos en GLib}
 Los hilos permiten que un programa realice varias tareas de manera simultánea. Tradicionalmente, los sistemas operativos tipo UNIX\begin{small}™\end{small}/Linux\begin{small}™\end{small} han utilizado los procesos para este propósito. No obstante, éstos son mucho más pesados (requieren más recursos) que los hilos.

Sin embargo, cada sistema operativo ha implementado de una forma diferente el concepto de hilo y, como resultado, las implementaciones no son compatibles, aunque sean muy parecidas. Ésto implica que si, se desea usar hilos en el programa será necesario proveer de una implementación diferente para cada sistemas operativo tipo UNIX.

GLib solventa este problema ocultando las implementaciones especificas de cada plataforma y proveyendo de un API que puede ser accedido de la misma forma desde cualquier sistema operativo. No obstante, internamente se usará las llamadas nativas disponibles en la plataforma donde se encuentre la aplicación. Es decir, GLib abstrae la implementación de los hilos.

Antes de entrar en materia, es necesario hacer una observación: todos los hilos que un programa crea, comparten el mismo espacio de direcciones; esto es, se podrá acceder a las variables globales de nuestro programa (para lectura y escritura) desde cualquier hilo.

\subsection{Creación e inicialización de hilos}
\subsubsection{Inicialización}
Para poder trabajar con hilos, primero es necesario inicializar el sistema
de hilos con la siguiente instrucción:

\lstset{showspaces=false,backgroundcolor=\color{Grey},basicstyle=\small,stringstyle=\ttfamily,numbers=left,numberstyle=\tiny}
\begin{lstlisting}[language=C]
 void g_thread_init( GThreadFunctions *vtable );
\end{lstlisting}

\texttt{GThreadFunctions} es una tabla de funciones que usa la función
\texttt{g\_thread\_init()} para inicializar el sistema de hilos. Lo normal es
que dicho parámetro sea pasado como valor \texttt{NULL}, en cuyo caso GLib se
encarga de buscar los parámetros más apropiados.

A esta función sólo se debe de llamar una vez, ya que si se llamará más veces
el programa abortaría su ejecución. Para poder evitar esto, se podría
realizar lo siguiente:

\lstset{showspaces=false,backgroundcolor=\color{Grey},basicstyle=\small,stringstyle=\ttfamily,numbers=left,numberstyle=\tiny}
\begin{lstlisting}[language=C]
 if( !g_thread_supported() )
    g_thread_init( NULL );
\end{lstlisting}

La función \texttt{g\_thread\_supported} devuelve \texttt{TRUE} si el sistema de hilos está inicializado o \texttt{FALSE} en caso contrario.


\subsubsection{Creación}

Para la creación de un hilo se hace uso de la función \texttt{g\_thread\_create}:

\begin{lstlisting}[language=C]
 GThread* g_thread_create (GThreadFunc func, gpointer data,
                            gboolean joinable, GError **error);
\end{lstlisting}
donde:

\begin{itemize}
 \item \texttt{func}: es la función que se ejecutará en el nuevo hilo.
 \item \texttt{data}: argumentos que se le pasan al nuevo hilo para la función.
 \item \texttt{joinable}: especifica si el hilo creado es o no compatible con la función \texttt{g\_thread\_join()} para la sincronización entre diversos hilos.
 \item \texttt{error}: puede ser \texttt{NULL} para ignorar los erroes o no \texttt{NULL} para que presente un informe de errores en caso de error (sólo se generará dicho informe en caso de que falle la creación del hilo).
\end{itemize}

La función devuelve el hilo creado si ha tenido éxito o \texttt{NULL} en caso contrario. El hilo creado posee el nivel de prioridad por defecto. En caso de que se necesiten hilos con prioridad y el sistema operativo lo permita, se deberá trabajar con la función \texttt{g\_thread\_create\_full()} (aunque se recomienda sólo su uso cuando no sea posible la utilización de \texttt{g\_thread\_create()}).

A continuación se muestra un extracto de código donde se usa la función \texttt{g\_thread\_create()}:

\begin{lstlisting}[language=C]
 Gthread *hilo;
 hilo = g_thread_create ( funcion_hilo, NULL, FALSE, NULL );
\end{lstlisting}



\subsection{Sincronización de hilos}
\subsubsection{Join}
\begin{lstlisting}[language=C]
 gpointer g_thread_join (GThread *thread);
\end{lstlisting}
donde el \texttt{thread} es el GThread que se desea esperar. \texttt{thread} debe haber sido creado con el atributo \texttt{joinable=TRUE} en su creación (\texttt{g\_thread\_create()}. 

El valor devuelto por \texttt{g\_thread\_join} es el valor devuelto por \texttt{thread} al que se espera (una llamada a la función \texttt{g\_thread\_exit()} o por la función que este ejecutando).
\\


\subsubsection{GMutex}
Los mutex (del inglés, \textit{mutual exclusion}) o cerrojos se pueden entender como una especie de cerrojo que permite conocer si es posible o no acceder a una sección de código por lo general crítico. Si por ejemplo, una varibale está protegida por un mutex, se podría conocer el estado del mutex para saber si en ese momento existe otro hilo accediendo a dicha variable. Si la variable estuviera libre, sería posible acceder a ella \textit{tomando la llave del cerrojo}, hacer las operaciones oportunas con ella, y después reabrir el cerrojo de nuevo para que el siguiente hilo pueda acceder a la variable.

Para proteger una zona de datos del acceso compartido por varios hilos, GLib dispone de la estructura \texttt{GMutex} y de las funciones \texttt{g\_mutex\_lock} y \texttt{g\_mutex\_unlock}. Ambas reciben como argumento una variable de tipo GMutex previamente inicializado con la función \texttt{g\_mutex\_new()}. 
\begin{lstlisting}[language=C]
 GMutex* g_mutex_new();
 void g_mutex_free(GMutex *mutex);
 void g_mutex_lock (GMutex *mutex);
 void g_mutex_unlock (GMutex *mutex);
 gboolean g_mutex_trylock(GMutex *mutex);
\end{lstlisting}
\begin{itemize}
\item \texttt{g\_mutex\_new}: crea un nuevo mutex.
\item \texttt{g\_mutex\_free}: destruye un mutex.
\item \texttt{g\_mutex\_lock}: intenta adquirir el mutex y si éste ya había sido adquirido por otro hilo, el hilo actual se quedará bloqueado hasta que el anterior hilo lo libere.
\item \texttt{g\_mutex\_unlock}: libera el mutex. Si algún hilo se había quedado bloquedo al intentar adquirir el mutex, ese hilo se desbloquea y adquiere el mutex.
\item \texttt{g\_mutex\_trylock}: igual que \texttt{g\_mutex\_lock} pero si el mutex ya había sido adquirido por otro hilo devolverá \texttt{False} en caso contrario adquiere el mutex y devuelve \texttt{True}. 
\end{itemize}

En el siguiente ejemplo estraído de \footnote{\href{http://library.gnome.org/devel/glib/2.6/glib-Threads.html}{documentación de Glib}} podemos ver como hacer uso de GMutex:

\begin{lstlisting}[language=C]
static GMutex *give_me_next_number_mutex = NULL;

  void init_give_me_next_number () 
  {
    g_assert (give_me_next_number_mutex == NULL);
    give_me_next_number_mutex = g_mutex_new ();
  }

  int give_me_next_number ()
  {
    static int current_number = 0;
    int ret_val;

    g_mutex_lock (give_me_next_number_mutex);
    ret_val = current_number = calc_next_number (current_number); 
    g_mutex_unlock (give_me_next_number_mutex);
    return ret_val;
  }
\end{lstlisting}

Es importante notar que es necesario inicializar el GMutex antes de hacer alguna llamada a la función en la que se hace uso del GMutex \texttt{give\_me\_next\_number}. La sección crítica en la cual se necesita una exclusión mutua se empieza con la función \texttt{g\_mutex\_lock} y termina con la función \texttt{g\_mutex\_unlock}. Antes de poder inicializar un GMutex también será necesario llamar a la función \texttt{g\_thread\_init()}.

% \subsubsection{GStaticMutex}
% La estructura \texttt{GStaticMutex} funciona de manera similar que \texttt{GMutex}, pero con una principal ventaja. \texttt{GStaticMutex} no necesita ser creado en tiempo de ejecución como ocurre con \texttt{GMutex}, 


\newpage
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\section{DBus}
\subsection{Introducción}
Cuando los creadores de KDE y Gnome comenzaron a diseñarlos enseguida se dieron cuenta de la necesidad de crear un sistema de objetos. Cada ventana, cada botón y cada etiqueta están conectados y se mandan mensajes entre ellos. KDE decidió programar sus sistemas en C++. Gnome, en cambio, decidió usar C. 

Desde un primer momento aparecieron problemas. Por ejemplo, la papelera de reciclaje de Gnome no era la misma que la de KDE, los escritorios no se guardaban en el mismo directorio, etc. Lo peor de todo era que las aplicaciones de ambos escritorios no podían comunicarse entre ellas.
   
KDE usaba para comunicar a sus aplicaciones el protocolo DCOP\footnote{\href{http://developer.kde.org/documentation/other/dcop.html}{http://developer.kde.org/documentation/other/dcop.html}} de creación propia, un protocolo diseñado exclusivamente para él. Es pequeño, ligero y simple. Gnome empleaba Corba\footnote{\href{http://www.corba.org/}{http://www.corba.org/}}, un protocolo ``diseñado por comité'', tan ambicioso que jamás se ha llegado a usar completamente. 

Desde un príncipio se realizaron críticas de uno y otro lado. Desde KDE se criticaba el sistema de Gnome diciendo que era demasiado grande y demasiado lento. Por su parte, la gente de Gnome criticaba el sistema de KDE diciendo que era demasiado pequeño y no era compatible con Corba, que es un estándar mundial.
   
Dicha situación se ha venido prolongado durante los años y se hacía patente una solución imparcial para ambos proyectos. Y dicha solución ha consistido en eliminar el problema en lugar de solucionarlo: una entidad independiente, FreeDesktop\footnote{\href{http://www.freedesktop.org}{http://www.freedesktop.org}}, comenzó el diseño de DBus\footnote{\href{http://dbus.freedesktop.org}{http://dbus.freedesktop.org}} de forma autónoma. DBus permitiría a los programas intercambiar información. Tiene lo mejor de Corba y DCOP, pero no pretende ser la solución final al problema del intercambio de información entre procesos. Su objetivo es claro: comunicar a las aplicaciones dentro de una misma sesión de escritorio.

Al no pertenecer a ninguno de los dos escritorios, ha sido adoptado junto a un paquete de otras compatibilidades, como por ejemplo, a la papelera de reciclaje común comentada en líneas anteriores. 
   
\subsection{El protocolo DBus}
DBus es un protocolo de comunicación entre procesos que emplea mensajes. Ha sido diseñado para que sea ligero y fácilmente empotrable en cualquier programa. Pero la pregunta que le puede surgir a un programador es para qué quiere o necesita un sistema como DBus.

Pues bien, las aplicaciones de nuestro escritorio hacen uso de servicios. Podemos pensar en todo aquello que es común encontrar en las aplicaciones: un sistema de avisos, el portapapeles o la impresión. La función del escritorio es proveer estos servicios de forma que la creación de aplicaciones sea mucho más sencilla para los desarrolladores.

Gnome y KDE ofrecen estos servicios, pero de forma incompatible. Digamos que tienes Gnome arrancado y que ejecutas un programa para KDE. El programa de KDE espera una serie de servicios ofrecidos a través de DCOP, pero GNOME los ofrece a través de Corba. Lo mismo ocurriría en la situación inversa.

Tanto Gnome como KDE están adoptando DBus como su sistema de comunicaciones. Se espera que la interacción entre las aplicaciones de los dos grandes escritorios de Linux sea una realidad en un futuro próximo.

\subsection{Conceptos básicos}
La arquitectura de DBus se compone principalmente de 3 partes:
\begin{itemize}
\item La librería de bajo nivel \texttt{libdbus}.
\item Un daemon que sirve como repetidor de los mensajes.
\item Un conjunto de API's de más alto nivel sobre la librería libdbus.
\end{itemize}

La ``\textit{envoltura}'' se encarga de mantener todos los detalles ocultos. De esta forma podremos trabajar de manera más sencilla. La relación entre estos tres componentes se muestra en la figura \ref{img:esqdbus}.

\begin{figure}[ht!]
\begin{center}
\scalebox{0.52}{\includegraphics{imagenes/esqdbus.jpg}}
\end{center}
\caption{Esquema de la arquitectura DBus}
\label{img:esqdbus}
\end{figure}

   
Por su parte, la librería \texttt{libdbus} crea conexiones o canales que conectan dos aplicaciones. Lo que hacemos
es usar esa única conexión para engancharnos al daemon de DBus, que se comporta como un repetidor. De esta forma todas las aplicaciones que se conecten al \textit{daemon} podrán contactar entre sí.

La información se transmite en forma de mensajes. Los hay de dos tipos: métodos y señales. Los métodos sirven para decirle a un objeto que realice una operación. Pueden requerir parámetros o no. Mientras, las señales sirven
para notificar un suceso de interés general.

DBus es independiente del lenguaje que usemos para acceder a él. El acceso puede hacerse desde varios lenguajes como pueden ser Python, C o C\#. En DBus los objetos son unas entidades no asociadas a ningún lenguaje.

Un objeto en DBus es una ruta. En DBus los objetos son direccionados a través de una ruta que equivale a su nombre. Un programa publicará ``objetos-rutas'' a las que podremos acceder. Las rutas tienen un formato que nos
debe resultar familiar:

\begin{lstlisting}[language=C]
  /a/b/c.../n
\end{lstlisting}
Son rutas como las que se emplean en el sistema de ficheros de Linux.

Cada aplicación debe tener una ruta única. Es común que se emplee la dirección URL de la página web del proyecto que mantiene y desarrolla esa aplicación, así no es complicado encontrar rutas como:
\begin{itemize}
\item \texttt{/net/sf/gaim}
\item \texttt{/org/freedesktop/DBus}
\end{itemize}

A cada objeto le corresponden unos métodos. Es igual, por ejemplo, que en el lenguaje Python: un objeto guarda una
cantidad de información y unos métodos. Estos métodos cambiarán el estado del objeto o nos permitirán recabar información sobre él. Si queremos ver métodos y señales en funcionamiento sólo tenemos que ejecutar el comando dbus-monitor en una consola de texto y ver cómo se suceden las acciones (figura \ref{img:dbusmonitor}).

\begin{figure}[ht!]
\begin{center}
\scalebox{0.52}{\includegraphics{imagenes/dbusmonitor.jpg}}
\end{center}
\caption{Ejecución de dbus-monitor}
\label{img:dbusmonitor}
\end{figure}

\subsection{Los interfaces}
Si cada objeto publicase los métodos que quisiera sería muy complicado hacer algo genérico con DBus. ¿Cómo sabría una aplicación genérica el modo de contactar con los programas en ejecución? Este mismo problema surge también en el
diseño orientado a objetos, y ambos se han solucionado de la misma manera.

Los interfaces son conjuntos de métodos con nombres predefinidos y acciones acordadas que son conceptualmente cercanos. Un interfaz puede contener todo lo necesario para reproducir música o buscar texto. Los interfaces pueden tener la misma ruta que los objetos. Para poder diferenciarlos se llegó a un acuerdo:
\begin{itemize}
\item Los objetos tienen rutas con el carácter ``\texttt{/}'' como separador.
\item Los interfaces tienen rutas con carácter ``\texttt{.}'' como separador.
\end{itemize}

Por ejemplo, \texttt{/org/freedesktop/DBus} es un ruta y \texttt{org.freedesktop.DBus} es un interfaz.

Imaginemos que queremos que todos nuestros programas se puedan apagar remotamente. Podríamos crear un interfaz que sólo ofreciese el método apagar. Podríamos llamar a este interfaz, es.linux.magazine.apagar. Los programas podrían implementar dentro de sus objetos DBus este interfaz y de esa manera nuestro programa podría apagar todos los programas del sistema, dando igual en qué lenguaje estuviesen programados.

Cualquiera que haya estado un poco al tanto de las noticias sobre los últimos sistemas operativos de Apple o Microsoft habrá notado la importancia de la búsqueda en el escritorio. El software libre no se ha quedado de brazos cruzados y también ha desarrollado tecnología de este tipo. De hecho, DBus es la piedra angular para ello. Todos los programas pueden implementar un interfaz a través del cual se pueda realizar una búsqueda usando una cadena de texto.
 
Con sólo invocar al método busca con una cadena, cada programa te ofrecería los resultados encontrados de una forma establecida. Así es posible crear un programa que buscara
en todos ellos. Ese programa tiene nombre, se llama \textit{beagle}.


\subsection{Breve introducción a los bindings de GLib de DBus}

Los bindings de GLib de DBus añaden una capa de abstracción que facilitan el uso de las funcionalidades de DBus. 
A continuación se explican los pasos necesarios para realizar una llamada a una función de DBus expuesta por un programa en ejecución. 

Lo primero es incluir en nuestro programa las cabeceras \texttt{dbus/dbus.h} y \texttt{dbus/dbus-lib.h}. Para poder establecer comunicación con otro programa será necesario inicializar un dato de tipo DBusGConnection que representa el bus de conexión. Para ello utilizaremos la función \texttt{dbus\_g\_bus\_get} cuya definición es:

\begin{lstlisting}[language=C]
 DBusGConnection* dbus_g_bus_get(DBusBusType type, GError **error)
\end{lstlisting}

type indica el tipo de sesión de DBus que por ejemplo para comunicarse con otro programa se debe usar la constante \texttt{DBUS\_BUS\_SESSION}. En error se almacenan los errores que han podido ocurrir durante la llamada a la función.

Lo siguiente para poder enviar un mensaje por DBus será inicializar un dato de tipo DBusGProxy. Este dato se puede inicializar con la siguiente función:

\begin{lstlisting}[language=C]
DBusGProxy*         dbus_g_proxy_new_for_name           (DBusGConnection *connection,
                                                         const char *name,
                                                         const char *path,
                                                         const char *interface);
\end{lstlisting}
Donde:
\begin{itemize}
 \item \texttt{connection} es una conexión de DBus anteriormente inicializada.
 \item \texttt{name} es el nombre del servicio al que queremos conectar el proxy.
 \item \texttt{path} indica el objeto al que queremos utilizar.
 \item \texttt{interface} indica la interfaz que queremos utilizar.
\end{itemize}
Por último para realizar una llamada a un método necesitamos la siguiente función:
\begin{lstlisting}[language=C]
 gboolean            dbus_g_proxy_call                   (DBusGProxy *proxy,
                                                         const char *method,
                                                         GError **error,
                                                         GType first_arg_type,
                                                         ...);
\end{lstlisting}
Donde:
\begin{itemize}
 \item \texttt{proxy} es un proxy ya inicializado a través del cual realizamos la llamada.
 \item \texttt{method} es el nombre del método que queremos invocar
 \item \texttt{error} almacenará los errores ocurridos durante la llamada a la función
 \item \texttt{first\_arg\_type} el tipo del argumento que recibe/devuelve la función que invocamos (G\_TYPE\_STRING, G\_TYPE\_STRV, ...)
\end{itemize}
Cada argumento que queramos pasar a la función de DBus que invocamos estará seguida del tipo del argumento y los argumentos que se envían se separan de los que se reciben mediante el tipo G\_TYPE\_INVALID, el último argumento debe ser G\_TYPE\_INVALID.

\subsection{Compilación}

Compilar un proyecto utilizando las librerías de Gtk, GLib y DBus se puede hacer como en el siguiente Makefile de ejemplo 
\begin{lstlisting}
CFLAGS=-g -MMD -Wall `pkg-config --cflags gtk+-2.0 dbus-1 glib-2.0 dbus-glib-1 gthread-2.0`
LDFLAGS=`pkg-config --libs gtk+-2.0 glib-2.0 dbus-1 glib-2.0 dbus-glib-1 gthread-2.0`
all: main

main: main.c

\end{lstlisting}

\section{Aplicación de ejemplo}
\subsection{Propósito}

La aplicación implementada y que a continuación se expondrá su código no tiene otro propósito que el de demostrar cómo se haría una aplicacion sencilla utilizando las librerías GLib y Gtk y además haciendo uso de DBus.

Nuestra aplicación permite, a través de la interfaz de DBus del programa de mensajería instantánea \href{http://kopete.kde.org}{Kopete} de KDE 4, programar el envío de mensajes a contactos que no se encuentran conectados. Se selecciona un contacto, se escribe un mensaje y se hace click sobre el botón de añadir. El mensaje será enviado cuando el contacto se encuentre \emph{on-line} o inmediatamente si ya lo está.

Es necesario que el programa Kopete se esté ejecutando o el programa no se inicializará.

\begin{figure}[ht!]
\begin{center}
\scalebox{0.52}{\includegraphics{imagenes/snapshot1.png}}
\end{center}
\caption{Aplicación de ejemplo}
\label{img:exampleapp}
\end{figure}
\subsection{Funcionamiento}
Al inicializarse el programa obtiene por una función de DBus de Kopete la lista de todos los contactos con la que rellena el combo box superior del programa. Cuando se hace click sobre el botón de añadir se lanza un nuevo hilo que se encargará de comprobar también a través de DBus si el contacto está conectado y enviar el mensaje. Si el contacto no está conectado se realiza una espera activa en el que el hilo duerme durante 5 segundos. Una vez enviado el mensaje este se elimina de la lista de mensajes pendientes y el hilo termina.

\subsection{Bugs conocidos}
El programa saldrá con un mensaje \emph{Aborted} cuando Kopete no se esté ejecutando porque suponemos que ese se estará ejecutando. 

Al ser un programa sencillo de ejemplo no hemos realizado una comprobación extensiva de posibles casos que podrían ocasionar un mal funcionamiento del programa.

\subsection{Problemas encontrados}
En principio se había pensado desarrollar esta aplicación de ejemplo para que hiciera uso de la interfaz de DBus del programa de mensajería \href{http://www.pidgin.im}{Pidgin} de GNOME, pero la escasa documentación y la imposibilidad de averiguar qué métodos expone Pidgin en su interfaz mediante introspección nos llevó a cambiar a Kopete.

Averiguar qué funciones exponía Kopete resultó más fácil ya que por introspección utilizando qdbus si que era posible. Por otro lado no todas las funciones necesarias se encontraban implementadas aún, ya que Kopete de KDE 4 se encuentra en una fase temprana de desarrollo. 

En nuestro caso por ejemplo, podíamos averiguar la lista de contactos conectados, pero sólo podíamos obtener su e-mail cuando para enviar un mensaje era necesario hacerlo indicando el alias del contacto. Una función que dado un e-mail de un contacto devuelva su alias se encuentra implementada en la versión de desarrollo de Kopete pero no en el paquete que hemos utilizado. Para paliar ese problema y poder probar la aplicación lo que podíamos hacer es seleccionar las propiedades de un contacto con el botón derecho del ratón y poner su alias de manera manual como su e-mail.

\subsection{Código}
\begin{lstlisting}[language=C,basicstyle=\scriptsize]
#include <gtk/gtk.h>
#include <glib.h>
#include <glib-object.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <dbus/dbus.h>
#include <dbus/dbus-glib.h>


#define DBUS_SERVICE_KOPETE      "org.kde.kopete"
#define DBUS_PATH_KOPETE         "/Kopete"
#define DBUS_INTERFACE_KOPETE    "org.kde.Kopete"

DBusGConnection *bus;
DBusGProxy *dbus_proxy;
GError *error = NULL;

GtkWidget *list;
GList *listnodes;


enum
{
   COL_NAME = 0,
   COL_MSG,
   NUM_COLS
};


typedef struct {
   gchar *id;
   gchar *msg;
   gboolean inlist;
   GtkListStore *store;
   GtkTreeIter iter;
} node;


typedef struct {
   GtkWidget *combo;
   GtkWidget *msg;
   GtkWidget *list;
} info;

info sel;


gint delete_event(GtkWidget *widget, GdkEvent *event, gpointer data){
   return ( FALSE );
}

void destroy (GtkWidget *widget, gpointer data){
   gtk_main_quit ();
}



static GtkWidget * create_and_fill_combo_box( void ){

   g_type_init ();

   gchar **name_list;
   gchar **name_list_ptr;
   GtkWidget *combo;
    
   GtkListStore *cmb_store;
   GtkTreeIter cmb_iter;
   GtkCellRenderer *rend;
   rend = gtk_cell_renderer_text_new ();
    
   GList *glist = NULL;    
    
   cmb_store = gtk_list_store_new (1, G_TYPE_STRING);
    
   combo = gtk_combo_box_new_with_model(GTK_TREE_MODEL( cmb_store ));
    
   gtk_cell_layout_pack_start (GTK_CELL_LAYOUT(combo), rend, TRUE);
   gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT(combo), rend, "text", 0);


   /* Get the bus */
   bus = dbus_g_bus_get (DBUS_BUS_SESSION, &error);
   if (bus == NULL) {
      g_printerr("Failed to open connection to bus: %s", error->message);
      g_error_free(error);
      return gtk_combo_box_new();
   }

   /* Create a proxy object for the bus driver */
   dbus_proxy = dbus_g_proxy_new_for_name (bus, DBUS_SERVICE_KOPETE, DBUS_PATH_KOPETE, DBUS_INTERFACE_KOPETE);
    
   if (!dbus_proxy) {
      g_printerr("Couldn't connect to the Purple Service: %s", error->message);
      g_error_free(error);
      return gtk_combo_box_new();
   }

   if(dbus_g_proxy_call (dbus_proxy, "contacts", &error, G_TYPE_INVALID, G_TYPE_STRV, &name_list, G_TYPE_INVALID)){
      for (name_list_ptr = name_list; *name_list_ptr; name_list_ptr++){       
         glist = g_list_insert_sorted( glist, g_strsplit(*name_list_ptr, ":", 3)[2], g_ascii_strcasecmp );
      }
      GList *li;
   
      for (li = glist; li != NULL; li = g_list_next(li)){
         gtk_list_store_append (cmb_store, &cmb_iter);
         gtk_list_store_set (cmb_store, &cmb_iter, 0, li->data, -1);
      }
      g_list_free(li);

   }
    
   g_strfreev (name_list);
   g_list_free( glist );
    
   return combo;
}


static void init_list(GtkWidget *list){

   GtkCellRenderer    *renderer;
   GtkListStore       *store;

   renderer = gtk_cell_renderer_text_new();
   gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (list), -1, "Nombre", renderer, "text", COL_NAME, NULL);
   renderer = gtk_cell_renderer_text_new();
   gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (list), -1, "Mensaje",   renderer, "text", COL_MSG, NULL);
   
//    column = gtk_tree_view_column_new_with_attributes("List Item", renderer, "text", LIST_ITEM, NULL);
//    gtk_tree_view_append_column(GTK_TREE_VIEW (list), column);

   store = gtk_list_store_new (NUM_COLS, G_TYPE_STRING, G_TYPE_STRING);

   gtk_tree_view_set_model(GTK_TREE_VIEW (list), GTK_TREE_MODEL(store));

   g_object_unref(store);
}


gchar* getText(){
   gchar *mes; 
   GtkTextBuffer *buffer;
   GtkTextIter start;
   GtkTextIter end;
          
   buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(sel.msg));
   gtk_text_buffer_get_start_iter(GTK_TEXT_BUFFER (buffer), &start);
   gtk_text_buffer_get_end_iter  (GTK_TEXT_BUFFER (buffer), &end);
    
   mes = gtk_text_buffer_get_text (GTK_TEXT_BUFFER (buffer), &start, &end, TRUE); 
   return mes;    
}



void launch(gpointer n2){
   node *n= n2;
   gboolean borrado = FALSE, conectado=FALSE;
   gchar **lst_contact;
   gchar **l_ptr;
   gchar * aux, *id, *msg;
   GError *error = NULL;
   GtkListStore *store;
   GtkTreeIter  iter;
   gboolean inlist;
   
   id=n->id;
   msg=n->msg;
   store= n->store;
   iter=n->iter;
   inlist=n->inlist;
   
   g_print(" > Mensaje '%s' para %s\n", n->msg, id);
   
   while( inlist && !borrado){
      if(dbus_g_proxy_call (dbus_proxy, "contactsByFilter", &error, G_TYPE_STRING, "online", G_TYPE_INVALID, G_TYPE_STRV, &lst_contact, G_TYPE_INVALID)){
         for (l_ptr = lst_contact; *l_ptr && !conectado; l_ptr++){
            aux = g_strsplit(*l_ptr, ":", 3)[2];
            if(!g_ascii_strcasecmp(aux, id)){
               g_print("El contacto %s esta conectado\n", id);
               conectado = TRUE;
            }           
         }
      }
      g_print("Mensaje %s\n", msg);
      if(conectado){
         if(dbus_g_proxy_call (dbus_proxy, "sendMessage", &error, G_TYPE_STRING, id, G_TYPE_STRING, msg, G_TYPE_INVALID,  G_TYPE_INVALID)){
            inlist = FALSE;
         }
      }
      else{
         g_print("Entramos en espera\n");
         g_usleep(5000000);
         g_print("Salimos de la espera\n");
      }
   }
   gtk_list_store_remove(store, &iter);
}


static void append_item(GtkWidget *widget, gpointer entry){
   
   GtkListStore *store;
   GtkTreeIter  iter;
   gchar *mes, *per;
   GThread *hilo;

   node n;   
   
   mes = getText();
   g_print ("Texto: %s \n", mes);

   //Get contact id
   per = gtk_combo_box_get_active_text(sel.combo);
   g_print ("Texto: %s \n", per);
   
    store = GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(list)));
   
    gtk_list_store_append (store, &iter);
    gtk_list_store_set (store, &iter, COL_NAME, per, COL_MSG, mes, -1);
   
   n.id = per;
   n.msg = mes;
   n.inlist = TRUE;
   n.store = store;
   n.iter = iter;
   hilo = g_thread_create (launch, &n, FALSE, NULL);
  
   listnodes = g_list_append(listnodes, &n);
   
}

static void remove_item(GtkWidget *widget, gpointer selection){
   GtkListStore *store;
   GtkTreeModel *model;
   GtkTreeIter  iter;

   store = GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW (list)));
   model = gtk_tree_view_get_model (GTK_TREE_VIEW (list));

   if (gtk_tree_model_get_iter_first(model, &iter) == FALSE) 
      return;

   if (gtk_tree_selection_get_selected(GTK_TREE_SELECTION(selection),&model, &iter)) {
       gchar * name;
       gtk_tree_model_get (model, &iter, COL_NAME, &name, -1);
       g_print("cadena: %s\n", name);
       gtk_list_store_remove(store, &iter);
   }
}




int main(int argc, char *argv[]) {
   
   GtkWidget *window;
   GtkWidget *lbl_message, *lbl_contact, *lbl_list;
   GtkWidget *cmb_contact;
   GtkWidget *btn_add;
   GtkWidget *txt_message, *scroll;
   GtkWidget *scroll2;
   
   GtkWidget *hb_contact;
   GtkWidget *hb_buttons;
   GtkWidget *vb_main;
   GtkWidget *sw;
   
   GtkTreeSelection *selection;
   
   gtk_init (&argc, &argv);
   g_thread_init(NULL);
   dbus_g_thread_init();

   window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
   sw = gtk_scrolled_window_new(NULL, NULL);
   list = gtk_tree_view_new();
   
   
   gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW(sw), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);

   gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW(sw), GTK_SHADOW_ETCHED_IN);

   gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (list), FALSE);
   gtk_container_add(GTK_CONTAINER (sw), list);

   
   /* labels */
   lbl_message = gtk_label_new( "Mensaje:" );
   lbl_contact = gtk_label_new( "Contacto:" );
   lbl_list = gtk_label_new( "Mensajes pendientes:");
   
   /* combo box */
   cmb_contact = create_and_fill_combo_box(); 
   
   /* buttons */
   btn_add = gtk_button_new_with_label( "Anyadir" );

   /* text widget */
   scroll = gtk_scrolled_window_new (NULL, NULL);
   gtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW(scroll), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC );
   txt_message = gtk_text_view_new();
   gtk_container_add(GTK_CONTAINER (scroll), txt_message);

   init_list(list);
   selection  = gtk_tree_view_get_selection(GTK_TREE_VIEW(list));
   gtk_container_add(GTK_CONTAINER (scroll2), list);

   /* group boxes */
   hb_contact = gtk_hbox_new( FALSE, 5 );
   hb_buttons = gtk_hbox_new( TRUE, 5 );
   vb_main = gtk_vbox_new( FALSE, 5 );

   gtk_box_pack_start( GTK_BOX( hb_buttons ), btn_add, TRUE, TRUE, 0 );

   gtk_box_pack_start( GTK_BOX( hb_contact ), lbl_contact, TRUE, TRUE, 0 );

   gtk_box_pack_start( GTK_BOX( hb_contact ), cmb_contact, TRUE, TRUE, 0 );

   gtk_box_pack_start( GTK_BOX( vb_main ), hb_contact, TRUE, TRUE, 0 );
   gtk_box_pack_start( GTK_BOX( vb_main ), lbl_message, TRUE, TRUE, 5 );
   gtk_box_pack_start( GTK_BOX( vb_main ), scroll, TRUE, TRUE, 0 );

   gtk_box_pack_start( GTK_BOX( vb_main ), hb_buttons, TRUE, TRUE, 10 );
   gtk_box_pack_start( GTK_BOX( vb_main ), lbl_list, TRUE, TRUE, 10 );
   gtk_box_pack_start( GTK_BOX( vb_main ), sw, TRUE, TRUE, 0 );

   gtk_container_add( GTK_CONTAINER( window ), vb_main );
         

   gtk_signal_connect (GTK_OBJECT (window), "delete_event", G_CALLBACK (delete_event), NULL);
   gtk_signal_connect (GTK_OBJECT (window), "destroy", G_CALLBACK (destroy), NULL);
   gtk_signal_connect (GTK_OBJECT (btn_add), "clicked",G_CALLBACK ( append_item ) , selection);

   gtk_container_border_width (GTK_CONTAINER (window), 10);

   gtk_widget_show_all(window);
   
   sel.combo = cmb_contact;
   sel.msg = txt_message;
   sel.list = list;

   gtk_main ();

   return 0;
}

\end{lstlisting}

\newpage
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\section{Bibliografia}
\begin{itemize}
 \item \url{http://library.gnome.org/devel/}
 \item \url{http://library.gnome.org/devel/glib/stable/glib-Threads.html}
 \item \url{www.linuxlots.com/~barreiro/spanish/gtk/tutorial/gtk\_tut.es.html}
 \item \url{http://www.linux-magazine.es/issue/23/044-047\_PythonLM23.crop.pdf}
\item \url{http://dbus.freedesktop.org/doc/dbus-tutorial.html}
\end{itemize}

\end{document}
